#include "stdafx.h"
#include "Renderer.h"
#include "RenderingData.h"
#include "Model.h"
#include "InputLayoutManager.h"
#include "GraphicsResources.h"
#include "ShaderManager.h"
#include "StateManager.h"
#include "PointLight.h"
#include "Mesh.h"
#include "Material.h"

using namespace mgfx;

Renderer * mgfx::gRenderer = NULL;

Renderer::~Renderer()
{
	gRenderer = NULL;
}

void Renderer::init(ID3D10Device * device)
{
	mDevice = device;
	gRenderer = this;

	PointLight & light = RenderingData::Instance.Pointlight;
	light.Position = XMCOLOR3F(50, 20, 50);
	light.Diffuse = XMCOLOR3F(1, 1, 1);
	light.Ambient = XMCOLOR3F(0.4f, 0.4f, 0.4f);
	light.Specular = XMCOLOR3F(0.9f, 0.9f, 0.9f);

}

void Renderer::setView(const XMFLOAT4X4 & view)
{
	RenderingData::Instance.View = view;
	mCurrentView = view;
}

void Renderer::setProj(const XMFLOAT4X4 & proj)
{
	RenderingData::Instance.Projection = proj;
	mCurrentProj = proj;
}

void Renderer::setEyePos(const XMFLOAT3 & pos)
{
	RenderingData::Instance.EyePosition = pos;
}

void Renderer::addModel(ModelKey key, ModelDC * drawCall)
{
	mModels.push_back(pair<ModelKey, ModelDC*>(key, drawCall));
}

void Renderer::render()
{
	static float xxx = 0.0f;
	static bool up = true;
	if(up) {
		xxx += 1.1f;
		if(xxx >= 60.0f)
			up = false;
	}
	else {
		xxx -= 1.1f;
		if(xxx <= 0.0f)
			up = true;
	}
	//RenderingData::Instance.Pointlight.Position.x = 20.0f + xxx;

	XMMATRIX view, proj, viewProj;
	view = XMLoadFloat4x4(&mCurrentView);
	proj = XMLoadFloat4x4(&mCurrentProj);
	viewProj = XMMatrixMultiply(view, proj);
	XMStoreFloat4x4(&RenderingData::Instance.ViewProj, viewProj);

	//D3DXMatrixMultiply(&RenderingData::Instance.ViewProj, &mCurrentView, &mCurrentProj);

	//for(uint i=0 ; i<mModels.size() ; ++i)
	//{
	//	Shader * shader = mModels[i].second->Model->getMaterial()->Shader;
	//	shader->setParamsGlobal();
	//	shader->setParamsModel(mModels[i].second);

	//	mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	//	mDevice->IASetInputLayout(GraphicsResources::getGlobal()->getInputLayoutMgr()->PosTangentNormalTex);

	//	D3D10_TECHNIQUE_DESC techDesc;
	//	HR(shader->Tech->GetDesc( &techDesc ));

	//	for(uint j = 0; j < techDesc.Passes; ++j)
	//	{
	//		ID3D10EffectPass* pass = shader->Tech->GetPassByIndex(j);

	//		//for(uint subsetID = 0; subsetID < mNumSubsets; ++subsetID)
	//		{
	//			pass->Apply(0);
	//			mModels[i].second->Model->getMesh()->DrawSubset(0);
	//		}
	//	}
	//}


	ShaderID prevShaderID = NONE;
	Model * prevModelPtr = NULL;

	mDevice->IASetInputLayout(GraphicsResources::getGlobal()->getInputLayoutMgr()->PosTangentNormalTex);

	// ambient pass

	Shader * ambient = GraphicsResources::getGlobal()->getShaderMgr()->getShader(AMBIENT);
	ambient->setParamsGlobal();
	ambient->setStates(mDevice);
	
	for(uint i=0 ; i<mModels.size() ; ++i)
	{
		Model * model = mModels[i].second->Model;
		
		ambient->setParamsModel(mModels[i].second);

		D3D10_TECHNIQUE_DESC techDesc;
		HR(ambient->Tech->GetDesc( &techDesc ));

		for(uint j = 0; j < techDesc.Passes; ++j)
		{
			ID3D10EffectPass* pass = ambient->Tech->GetPassByIndex(j);

			//for(uint subsetID = 0; subsetID < mNumSubsets; ++subsetID)
			{
				pass->Apply(0);

				if(model != prevModelPtr)
				{
					HR(model->getMesh()->DXMesh->DrawSubset(0));
				}
				else
				{
					mDevice->DrawIndexed(model->getMesh()->NumIndices, 0, 0);
				}

			}
		}
		prevModelPtr = model;
	}

	// shadow volume rendering

	Shader * shadowVolume = GraphicsResources::getGlobal()->getShaderMgr()->getShader(SHADOW_VOLUME);
	shadowVolume->setParamsGlobal();
	shadowVolume->setStates(mDevice);
	
	for(uint i=1 ; i<mModels.size() ; ++i)
	{
		Model * model = mModels[i].second->Model;
		
		shadowVolume->setParamsModel(mModels[i].second);

		D3D10_TECHNIQUE_DESC techDesc;
		HR(shadowVolume->Tech->GetDesc( &techDesc ));

		for(uint j = 0; j < techDesc.Passes; ++j)
		{
			ID3D10EffectPass* pass = shadowVolume->Tech->GetPassByIndex(j);

			//for(uint subsetID = 0; subsetID < mNumSubsets; ++subsetID)
			{
				pass->Apply(0);

				if(model != prevModelPtr)
				{
					HR(model->getMesh()->DXMesh->DrawSubset(0));
				}
				else
				{
					mDevice->DrawIndexed(model->getMesh()->NumIndices, 0, 0);
				}

			}
		}
		prevModelPtr = model;
	}

	// regular rendering
	for(uint i=0 ; i<mModels.size() ; ++i)
	{
		Shader * shader = mModels[i].second->Model->getMaterial()->Shader;
		ShaderID shaderID = shader->ID;
		Model * model = mModels[i].second->Model;

		if(shaderID != prevShaderID)
		{
			shader->setParamsGlobal();
			shader->setStates(mDevice);
			mDevice->OMSetDepthStencilState(GraphicsResources::getGlobal()->getStateMgr()->getDepthStencilState(MGFX_DSS_AFTER_SHADOW_VOLUME_STENCIL), 0);
		}
		
		shader->setParamsModel(mModels[i].second);

		//mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
		

		D3D10_TECHNIQUE_DESC techDesc;
		HR(shader->Tech->GetDesc( &techDesc ));

		for(uint j = 0; j < techDesc.Passes; ++j)
		{
			ID3D10EffectPass* pass = shader->Tech->GetPassByIndex(j);

			//for(uint subsetID = 0; subsetID < mNumSubsets; ++subsetID)
			{
				//if(shaderID != prevShaderID)
				pass->Apply(0);

				if(model != prevModelPtr)
				{
					HR(model->getMesh()->DXMesh->DrawSubset(0));
				}
				else
				{
					mDevice->DrawIndexed(model->getMesh()->NumIndices, 0, 0);
				}

			}
		}

		prevShaderID = shaderID;
		prevModelPtr = model;
	}

	mModels.clear();
}